package com.edev.support.ddd.join;

import com.edev.support.dao.BasicDao;
import com.edev.support.dsl.Join;
import com.edev.support.entity.Entity;
import lombok.NonNull;

import java.io.Serializable;
import java.util.*;

/**
 * 一对一关系处理器（聚合关系实现）
 * <p>
 * 核心功能：
 * 1. 增删改时，处理聚合根与关联实体的级联操作
 * 2. 数据查询时，实现对关联实体的数据加载
 * 3. 批量加载关联实体的优化性能
 */
public class OneToOneForJoin<E extends Entity<S>, S extends Serializable> extends AbstractRelation<E,S> {
    /**
     * 构造方法
     * @param join 关系配置元数据
     * @param dao 关联实体的数据访问对象
     */
    public OneToOneForJoin(@NonNull Join join, @NonNull BasicDao dao) {
        super(join, dao);
    }

    /**
     * 插入主实体时，联级处理有聚合关系的关联实体
     * <p>
     * 处理流程：
     * 1. 检查是否存在聚合关系
     * 2. 从主实体中获取关联实体
     * 3. 执行对关联实体的插入操作
     * @param entity 聚合根实体对象（包含关联实体）
     */
    @Override
    public void insertValue(E entity) {
        if(entity==null||!join.isAggregation()) return;
        String name = join.getName();
        Entity<?> value = (Entity<?>) entity.getValue(name);
        if(value==null) return;
        dao.insert(value);
    }

    /**
     * 更新主实体时，联级处理有聚合关系的关联实体
     * <p>
     * 核心逻辑：
     * 1. 检查是否存在聚合关系
     * 2. 从主实体中获取关联实体
     * 3. 对关联实体执行插入/更新/删除操作
     * @param entity 聚合根实体对象（包含关联实体）
     */
    @Override
    public void updateValue(E entity) {
        if(entity==null||!join.isAggregation()) return;
        String name = join.getName();
        Entity<?> value = (Entity<?>) entity.getValue(name);
        if(value==null) deleteValue(entity);
        else dao.insertOrUpdate(value);
    }

    /**
     * 删除主实体时，联级处理有聚合关系的关联实体
     * <p>
     * 实现方式：
     * 根据聚合根ID直接删除关联实体
     * @param entity 聚合根实体对象（包含关联实体）
     */
    @Override
    public void deleteValue(E entity) {
        if(entity==null||!join.isAggregation()) return;
        S id = entity.getId();
        dao.delete(id, getClazz());
    }

    /**
     * 对单个实体加载关联实体
     * <p>
     * 查询方式：
     * 通过聚合根ID直接加载关联实体
     * @param entity 需要加载关联数据的聚合根
     */
    @Override
    public void setValue(E entity) {
        if(entity==null) return;
        S id = entity.getId();
        Entity<S> value = dao.load(id, getClazz());
        if(value==null) return;
        entity.setValue(join.getName(), value);
    }

    /**
     * 批量对多个实体加载关联实体（优化版）
     * <p>
     * 性能优化点：
     * 1. 批量收集所有实体需要关联的外键ID
     * 2. 单次批量从数据库或缓存中查找所有关联实体
     * 3. 建立ID-实体映射表，快速完成关联实体对实体对象的装配
     * @param list 需要加载关联数据的聚合根集合
     */
    @Override
    public void setValueForList(Collection<E> list) {
        if(list==null||list.isEmpty()) return;
        List<S> ids = new ArrayList<>();
        for(E entity : list) ids.add(entity.getId());
        Collection<Entity<S>> valueList = dao.loadForList(ids, getClazz());
        setListOfValuesToEachEntity(list, valueList);
    }

    /**
     * 为实体集合中的每个实体加载关联实体
     * <p>
     * 1. 遍历整个关联实体集合，建立ID-实体映射表
     * 2. 通过ID-实体映射表，快速完成关联实体对实体对象的装配
     * @param list 聚合根集合
     * @param valueList 关联实体集合
     */
    private void setListOfValuesToEachEntity(Collection<E> list, Collection<Entity<S>> valueList) {
        if(list==null||valueList==null||list.isEmpty()||valueList.isEmpty()) return;
        Map<S,Entity<S>> mapOfEntitiesNeedJoin = new HashMap<>();
        valueList.forEach(value->mapOfEntitiesNeedJoin.put(value.getId(), value));
        list.forEach(entity->{
            Entity<S> value = mapOfEntitiesNeedJoin.get(entity.getId());
            if(value==null) return;
            entity.setValueByMethod(join.getName(), value);
        });
    }
}
